﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using D5ScannerFPCWrapper;
using DPFP;
using DPFP.Capture;
using DPFP.Processing;
using DevExpress.XtraEditors;
using System.Reactive.Linq;

namespace TransLogger.Module.Win
{
    public partial class FingerEnrollmentForm : DevExpress.XtraEditors.XtraForm, DPFP.Capture.EventHandler
    {
        private DPFP.Processing.Enrollment _enrollment;
        private DPFP.Capture.Capture _capture;
        private D5ScannerFPCWrapper.D5ScannerFPC _fingerReader;
        private IDisposable _observer;
        private bool _fingerOn = false;

        public FingerEnrollmentForm()
        {
            InitializeComponent();
        }

        public void OnComplete(object Capture, string ReaderSerialNumber, Sample Sample)
        {
            var converter = new DPFP.Capture.SampleConversion();
            Bitmap bitmap = null;
            converter.ConvertToPicture(Sample, ref bitmap);
            Action<Image> ac = i => pictureEdit1.Image = i;
            this.pictureEdit1.BeginInvoke(ac, bitmap);

            var featureExtractor = new DPFP.Processing.FeatureExtraction();
            var feedback = CaptureFeedback.None;
            var featureSet = new FeatureSet();
            featureExtractor.CreateFeatureSet(Sample, DataPurpose.Enrollment, ref feedback, ref featureSet);
            if (feedback == CaptureFeedback.Good && featureSet != null)
            {
                _enrollment.AddFeatures(featureSet);
                switch (_enrollment.TemplateStatus)
                {
                    case DPFP.Processing.Enrollment.Status.Ready:	// report success and stop capturing
                        StopCapture();
                        UpdateSatus("指纹采集成功", true);
                        break;

                    case DPFP.Processing.Enrollment.Status.Failed:	// report failure and restart capturing
                        _enrollment.Clear();
                        StopCapture();
                        UpdateSatus("指纹采集失败，请重新采集", false);
                        StartCapture();
                        break;
                }
            }
        }

        public void OnFingerGone(object Capture, string ReaderSerialNumber)
        {
            this.UpdateSatus("请移开手指");
        }

        public void OnFingerTouch(object Capture, string ReaderSerialNumber)
        {
            this.UpdateSatus("手指触摸");
        }

        public void OnReaderConnect(object Capture, string ReaderSerialNumber)
        {
            this.UpdateSatus("指纹仪成功连接");
        }

        public void OnReaderDisconnect(object Capture, string ReaderSerialNumber)
        {
            this.UpdateSatus("指纹仪断开连接");
        }

        public void OnSampleQuality(object Capture, string ReaderSerialNumber, CaptureFeedback CaptureFeedback)
        {
            this.UpdateSatus(CaptureFeedback.Good == CaptureFeedback ? "指纹较好" : "指纹太差");
        }

        private void FingerEnrollmentForm_Load(object sender, EventArgs e)
        {
            InitCapture();
        }

        private void InitCapture()
        {
            _capture = new Capture();
            _capture.EventHandler = this;
            _enrollment = new Enrollment();

            var devices = D5ScannerFPC.EnumDevice();
            _fingerReader = new D5ScannerFPC();
            var suc = _fingerReader.OpenDevice(0);
            if (!suc)
            {
                MessageBox.Show("无法打开指纹仪");
            }
            else
            {
                StartCapture();
            }
        }

        private void FingerEnrollmentForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            StopCapture();
        }

        private void StartCapture()
        {
            _capture.StartCapture();
            _observer = Observable.Interval(TimeSpan.FromMilliseconds(500))
                      .ObserveOn(SynchronizationContext.Current)
                      .Subscribe(l => ReadFinger());

        }

        private void StopCapture()
        {
            _capture.StopCapture();
            if (_observer != null)
            {
                _observer.Dispose();
            }
            if (_fingerReader != null)
            {
                _fingerReader.Dispose();
            }
        }

        private void UpdateSatus(string status, bool okEnable = false)
        {
            Action<string> ac = s =>
                                    {
                                        this.labelControlStatus.Text = s;
                                        //labelControlFingerNeeded.Text = _enrollment.FeaturesNeeded.ToString();
                                        simpleButtonOK.Enabled = okEnable;
                                    };
            this.BeginInvoke(ac, status);
        }

        private void simpleButtonOK_Click(object sender, EventArgs e)
        {
            //this.Template = _enrollment.Template;
            DialogResult = DialogResult.OK;
        }

        // public Template Template { get; set; }
        public byte[] Feature { get; set; }

        private void simpleButton2_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //ReadFinger();
        }

        private void ReadFinger()
        {
            var img = _fingerReader.GetImage();
            var hasFinger = D5ScannerFPC.CheckFP(img);
            if (hasFinger)
            {
                if (!_fingerOn)
                {
                    _fingerOn = true;
                    var bmp = D5ScannerFPC.ToImage(img);
                    this.pictureEdit1.EditValue = bmp;
                    try
                    {
                        var feature = D5ScannerFPC.Process(img);
                        _fingerReader.Beep(40);
                        this.Feature = feature;
                        UpdateSatus("指纹采集成功", true);
                    }
                    catch (Exception ex)
                    {
                        UpdateSatus(ex.Message);
                    }

                }
            }
            else
            {
                _fingerOn = false;
            }
        }
    }
}